//#include <freetype.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <cairo.h>
#include <cairo/cairo-ft.h>
#include <gio/gio.h>

#define THUMB_SIZE 128
#define PADDING_VERTICAL 2
#define PADDING_HORIZONTAL 4

static gsize read_file(gchar* file, gchar** contents);
static FT_Face create_font_face(FT_Library library,
                                gchar* contents, gsize length);
static gint save_font_face(FT_Face face, gchar* dest);

static gsize
read_file(gchar* file, gchar** contents)
{
    GError* error = NULL;
    gsize length;

    g_file_get_contents(file, contents, &length, &error);
    if (error != NULL) {
        g_printerr("Load file '%s' failed: %s\n", file, error->message);
        g_error_free(error);
        return 0;
    }

    return length;
}

static FT_Face
create_font_face(FT_Library library, gchar* contents, gsize length)
{
    FT_Long index = 0;
    FT_Face face;
    FT_Error error = FT_New_Memory_Face(library,
                                        (const FT_Byte*)contents,
                                        (FT_Long)length,
                                        index,
                                        &face);
    if (error) {
        g_printerr("New font face failed\n");
        return NULL;
    }

    return face;
}

static gint
save_font_face(FT_Face face, gchar* dest)
{
    gint thumb_size = THUMB_SIZE;
    cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
                                                          thumb_size,
                                                          thumb_size);
    cairo_t* cr = cairo_create(surface);

    cairo_font_face_t *font = cairo_ft_font_face_create_for_ft_face(face, 0);
    cairo_set_font_face(cr, font);
    cairo_font_face_destroy(font);

    gint font_size = thumb_size - 2 * PADDING_VERTICAL;
    cairo_set_font_size(cr, font_size);
    cairo_text_extents_t text_extents;
    gchar* str = "Aa";
    cairo_text_extents(cr, str, &text_extents);

    gdouble scale_x, scale_y;
    if (text_extents.width > (thumb_size - 2 * PADDING_HORIZONTAL)) {
        scale_x = (gdouble)(thumb_size - 2 * PADDING_HORIZONTAL) / (text_extents.width);
    } else {
        scale_x = 1.0;
    }

    if (text_extents.height > (thumb_size - 2 * PADDING_VERTICAL)) {
        scale_y = (gdouble)(thumb_size - 2 * PADDING_VERTICAL) / (text_extents.height);
    } else {
        scale_y = 1.0;
    }

    gdouble scale = scale_x;
    if (scale < scale_y) {
        scale = scale_y;
    }
    cairo_scale(cr, scale, scale);

    cairo_translate(cr,
                    PADDING_HORIZONTAL - text_extents.x_bearing + (thumb_size - scale * text_extents.width) / 2.0,
                    PADDING_VERTICAL - text_extents.y_bearing + (thumb_size - scale * text_extents.height) / 2.0);

    // black
    cairo_set_source_rgba(cr, 0, 0, 0, 1.0);
    cairo_show_text(cr, str);
    cairo_destroy(cr);

    cairo_surface_write_to_png(surface, dest);
    cairo_surface_destroy(surface);

    return 1;
}

gint
gen_thumbnail(gchar* file, gchar* dest)
{
    FT_Error error;
    FT_Library library;

    error = FT_Init_FreeType(&library);
    if (error) {
        g_printerr("Could not init freetype\n");
        return -1;
    }

    gchar* contents;
    gsize length = read_file(file, &contents);
    if (length <= 0) {
        return -1;
    }

    FT_Face face = create_font_face(library, contents, length);
    if (face == NULL) {
        return -1;
    }

    save_font_face(face, dest);
    g_free(contents);

    error = FT_Done_Face(face);
    if (error) {
        g_printerr("Could not unload face\n");
        return -1;
    }

    error = FT_Done_FreeType(library);
    if (error) {
        g_printerr("Could not finalize freetype library\n");
        return -1;
    }

    return 0;
}

int
main(int argc, char* argv[])
{
    if (argc != 3) {
        g_print("Usage: <%s> <font file> <dest>\n", argv[0]);
        return -1;
    }

    return gen_thumbnail(argv[1], argv[2]);
}
